package cn.psh.basic.util.aop;

import cn.psh.basic.util.HttpContextUtil;
import cn.psh.basic.util.ServletUtils;
import cn.psh.basic.util.annotation.LogAnno;
import cn.psh.org.domain.Log;
import cn.psh.org.mapper.LogMapper;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


@Order(3)  // 标记支持AspectJ的切面排序
@Component
@Aspect
public class LogAopAspect {

    @Autowired
    private LogMapper LogMapper;

    @Pointcut("@annotation(cn.psh.basic.util.annotation.LogAnno)")
    public void operLogPoinCut() {

    }

    @AfterReturning(value = "operLogPoinCut()", returning = "keys")
    public Object aroundAdvice(JoinPoint joinPoint, Object keys) {

        // 1.方法执行前的处理，相当于前置通知
        // 获取方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        System.out.println("methodSignature:"+methodSignature);
        // 获取方法
        Method method = methodSignature.getMethod();
        System.out.println("method:"+method);
//        System.out.println(method);
        // 获取方法上面的注解
        LogAnno logAnno = method.getAnnotation(LogAnno.class);
        System.out.println(logAnno+"logAnno");
//        System.out.println(logAnno + "=======================");
        // 获取操作描述的属性值
        String operateType = logAnno.operateType();
        System.out.println("operateType:"+operateType);
        Log adminOperLog = new Log();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
        String className = joinPoint.getTarget().getClass().getName();
        String signatureName = methodSignature.getName();
        adminOperLog.setMethod(className + "." + signatureName + "()");
        String requestMethod = ServletUtils.getRequest().getMethod();
        if ("PUT".equals(requestMethod) || "POST".equals(requestMethod) || "GET".equals(requestMethod)) {
            String params = argsArrayToString(joinPoint.getArgs());
            adminOperLog.setParams(StringUtils.substring(params, 0, 2000));
        } else {
            // 获取RequestAttributes
            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            // 从获取RequestAttributes中获取HttpServletRequest的信息
            HttpServletRequest request = (HttpServletRequest) requestAttributes
                    .resolveReference(RequestAttributes.REFERENCE_REQUEST);
            // 请求的参数
            Map<String, String> rtnMap = converMap(request.getParameterMap());
            adminOperLog.setParams(StringUtils.substring(JSON.toJSONString(rtnMap), 0, 2000));
        }
        // 接口返回值参数
        adminOperLog.setOperateor("feifei");
        adminOperLog.setTime(simpleDateFormat.format(new Date()));
        adminOperLog.setType(operateType);
        String ip = HttpContextUtil.getIpAddress();
        adminOperLog.setIp(ip);
        Object result = null;
        LogMapper.save(adminOperLog);// 添加日志记录
        return result;
    }


    /**
     * 转换request 请求参数
     *
     * @param paramMap request获取的参数数组
     */
    public Map<String, String> converMap(Map<String, String[]> paramMap) {
        Map<String, String> rtnMap = new HashMap<String, String>();
        for (String key : paramMap.keySet()) {
            rtnMap.put(key, paramMap.get(key)[0]);
        }
        return rtnMap;
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                if (!isFilterObject(paramsArray[i])) {
                    Object jsonObj = JSON.toJSON(paramsArray[i]);
                    if (jsonObj != null) {
                        params += jsonObj.toString() + " ";
                    }
                }
            }
        }
        return params.trim();
    }

    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}

